home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Frameworks / Dragonsmith 1.1.1 / CW 4.5 Update / FileUtils.cp < prev    next >
Encoding:
Text File  |  1994-07-04  |  12.4 KB  |  349 lines  |  [TEXT/MMCC]

  1. /*
  2.     FileUtils.c
  3.     
  4.     Created    05 May 1992    Extracted from Dragon.c
  5.     Modified    28 May 1992    Changed parameters of FREFTypes
  6.                         Other very minor changes
  7.             29 May 1992    Added RefNumToFSSpec function — I finally figured out how to get an FSSpec from a path refNum
  8.             02 Aug 1992    Added FSpToPB, FSpToPBCatInfo, PBToFSp, and PBToFSpCatInfo — but they haven't been tested!
  9.             05 Aug 1992    Extensive rewrites and some testing of the FSSpec <=> PBRecUnion conversion functions — what I
  10.                             tested seemed to work just fine, but then I didn't test directories…
  11.             06 Aug 1992    Tuned up conversion functions
  12.             09 Aug 1992    FREFTypes now takes a parameter — the refnum of the resource fork to look in
  13.                         Added FSpFindFolder
  14.             16 Aug 1992    Fixed problems with ioDirID and ioFDirIndex in PBToFSpCatInfo
  15.             04 Sep 1992    Added FSpRefreshFinderDisplay (and it works!)
  16.             09 Sep 1992    Fixed bug in FREFTypes — it returned garbage if there were no 'FREF' resources
  17.             11 Sep 1992    Extracted PBToFSp, FSpType, and FSpOpenableType — Dragonsmith doesn't need them
  18.             18 Apr 1993    Rewrote PBToFSpCatInfo to overcome bug (?) in PBMakeFSSpec with directories on shared volumes
  19.                             — thanks to Paul van Mulbregt for pointing out the problem (which I should have spotted myself!)
  20.             30 May 1993    Fixed FREFTypes — it was DisposHandle'ing a resource (oops)
  21.             08 Aug 1993    Brought in DirectoryContentsLoop from its source file
  22.                         Added some safety measures to paramblock initializations
  23.             14 Aug 1993    Fiddled with code to get it to compile with type-checked <MacHeaders>
  24.             01 Jul 1994 by Francis H Schiffer, 3rd - add return value to RefNumToFSSpec
  25.  
  26.     Copyright © 1992–1993 by Paul M. Hoffman
  27.     Send comments or suggestions to paul.hoffman@umich.edu -or- dragonsmith@umich.edu
  28.     
  29.     This source code may be freely used, altered, and distributed in any way as long as:
  30.         1.    It is GIVEN away rather than sold (except as expressly permitted by the author)
  31.         2.    This statement and the above copyright notice are left intact.
  32.  
  33. */
  34.  
  35. #include    "FileUtils.h"
  36. #include    "StringUtils.h"
  37.  
  38. void FSpRefreshFinderDisplay (FSSpec *fss)
  39. {
  40.     // Given an FSSpec to a file, tell the Finder to update its display of the file's icon — also works for directories
  41.     // There will be a brief delay before the change is shown.  Experience indicates that the delay is noticeably longer
  42.     //    if the only change is in the case (upper vs. lower) of the file's name
  43.     
  44.     CInfoPBRec        pb;
  45.     OSErr            err;
  46.     unsigned long        secs;
  47.     
  48.     // Fill in the parameter block so we get info on the parent directory rather than the file/folder itself
  49.     pb.hFileInfo.ioCompletion = NULL;
  50.     pb.hFileInfo.ioNamePtr = NULL;
  51.     pb.hFileInfo.ioVRefNum = fss->vRefNum;
  52.     pb.hFileInfo.ioFVersNum = 0;                // To be on the safe side
  53.     pb.hFileInfo.ioFDirIndex = 0;
  54.     pb.hFileInfo.ioDirID = fss->parID;
  55.     
  56.     // Get info on the parent directory
  57.     if (PBGetCatInfoSync (&pb) == noErr) {
  58.         // Now change the parent directory's modified date
  59.         GetDateTime (&secs);
  60.         pb.dirInfo.ioDrMdDat = (unsigned long) secs;
  61.         (void) PBSetCatInfoSync (&pb);
  62.     }
  63. }
  64.  
  65. OSErr FSpOpenDataFork (FSSpec *fss, short *refNum, char *perm)
  66. {
  67.     // Open a file's data fork with fsRdPerm or (if possible) fsRdWrPerm
  68.     
  69.     OSErr    err;
  70.     char        permWanted = *perm;
  71.     
  72.     err = FSpOpenDF (fss, *perm, refNum);
  73.     if (err == noErr)
  74.         return err;
  75.     if ((err == opWrErr || err == permErr) && *perm == fsRdWrPerm) {
  76.         err = FSpOpenDF (fss, fsRdPerm, refNum);
  77.         *perm = fsRdPerm;
  78.     }
  79.     return err;
  80. }
  81.  
  82. OSErr FSpOpenResFork (FSSpec *fss, short *refNum, char *perm)
  83. {
  84.     // Open a file's resource fork with fsRdPerm or (if possible) fsRdWrPerm
  85.     
  86.     OSErr    err;
  87.     char        permWanted = *perm;
  88.     
  89.     *refNum = FSpOpenResFile (fss, *perm);
  90.     err = ResError ();
  91.     if (err == noErr)
  92.         return err;
  93.     if ((err == opWrErr || err == permErr) && *perm == fsRdWrPerm) {
  94.         *refNum = FSpOpenResFile (fss, fsRdPerm);
  95.         err = ResError ();
  96.         *perm = fsRdPerm;
  97.     }
  98.     return err;
  99. }
  100.  
  101. OSErr FSpFindFolder (OSType folderType, FSSpec *fss)
  102. {
  103.     // NOTE:    This function does NOT return an FSSpec to the folder in question; rather, it returns an FSSpec to an unnamed
  104.     //        file IN THAT FOLDER.  In other words, just fill in the name field of the FSSpec returned to get at a file in the folder
  105.     // If an error happens, *fss is not affected
  106.     
  107.     short    foundVRefNum;
  108.     long        foundDirID;
  109.     OSErr    err;
  110.     
  111.     err = FindFolder (kOnSystemDisk, folderType, kCreateFolder, &foundVRefNum, &foundDirID);
  112.     if (err == noErr) {
  113.         fss->vRefNum = foundVRefNum;
  114.         fss->parID = foundDirID;
  115.     }
  116.     return err;
  117. }
  118.  
  119. OSErr FSpToPB (PBRecUnion *pb, FSSpec *fss, Boolean resolveAFs, Boolean followAFChain, Boolean *wasAF)
  120. {
  121.     OSErr    err = noErr;
  122.     Boolean    isFolder;
  123.     
  124.     // Check for a NULL name pointer — prob. the most common mistake I make when using PB's
  125.     if (pb->h.fileParam.ioNamePtr == NULL)
  126.         return bdNamErr;        // This seems like a reasonable error code to use…
  127.         
  128.     if (resolveAFs)
  129.         err = ResolveAliasFile (fss, followAFChain, &isFolder, wasAF);
  130.     if (err == noErr) {
  131.         pb->h.fileParam.ioVRefNum = fss->vRefNum;
  132.         pb->h.fileParam.ioDirID = fss->parID;
  133.         pb->h.fileParam.ioFVersNum = 0;                        // To be on the safe side
  134.         SmartCopyPStr (fss->name, pb->h.fileParam.ioNamePtr);    // This ensures that .ioNamePtr points to a string exactly
  135.                                                         //    equivalent to fss->name
  136.     }
  137.     return err;
  138. }
  139.  
  140. OSErr FSpToPBCatInfo (PBRecUnion *pb, FSSpec *fss, Boolean resolveAFs, Boolean followAFChain, Boolean *wasAF)
  141. {
  142.     OSErr    err = noErr;
  143.     Boolean    isFolder;
  144.     
  145.     err = FSpToPB (pb, fss, resolveAFs, followAFChain, wasAF);
  146.     if (err == noErr) {
  147.         pb->c.hFileInfo.ioFDirIndex = 0;    // No indexing
  148.         err = PBGetCatInfoSync (&pb->c);
  149.     }
  150.     return err;
  151. }
  152.  
  153. OSErr PBToFSpCatInfo (PBRecUnion *pb, FSSpec *fss, Boolean resolveAFs, Boolean followAFChain, Boolean *wasAF)
  154. {    
  155.     // NOTE:    *wasAF will contain garbage if the error returned != noErr
  156.  
  157.     OSErr    err;
  158.     long        dirIDOrFileNum, ioDirIDWas;
  159.     Ptr        ioMiscWas;
  160.     short    ioFDirIndexWas;
  161.     Boolean    isFolder;
  162.     
  163.     // ASSERT — the ioNamePtr, ioVRefNum, ioFDirIndex, and ioDirID fields in *pb are valid
  164.     
  165.     // Check for a NULL name pointer — prob. the most common mistake I make when using PB's
  166.     if (pb->h.fileParam.ioNamePtr == NULL)
  167.         return bdNamErr;        // This seems like a reasonable error code to use…
  168.         
  169.     err = PBGetCatInfoSync (&pb->c);
  170.     if (err == noErr) {
  171.  
  172.         // ASSERT —    Most of the fields in *pb are now valid (unless the doc is an alias file and resolveAFs == TRUE,
  173.         //            in which case we've got the wrong file — calling ResolveAliasFile below will fix this, though, so don't worry!)
  174.     
  175.         // Now we're ready to make an FSSpec out of the paramblock
  176.         
  177.         // Calling PBMakeFSSpec here leads to problems on other shared volumes, so we do it by hand
  178.         
  179.         fss->parID = pb->c.hFileInfo.ioFlParID;
  180.         
  181.         // If resolveAFs == TRUE, then we need to check to see if this is an alias file — we can't
  182.         //    eliminate any file types, since in the future there may exist aliases to things (like maybe
  183.         //    mailboxes, in OCE) that didn't exist at the time this code was written.  We can, however,
  184.         //    be sure that only files can be alias files (kinda obvious, ain't it?)
  185.         
  186.         *wasAF = FALSE;
  187.  
  188.         if (err == noErr && resolveAFs && PBIsAliasFile (pb)) {
  189.             err = ResolveAliasFile (fss, followAFChain, &isFolder, wasAF);
  190.             if (err == noErr && *wasAF) {
  191.                 // If this was an alias file, we need to call PBGetCatInfo once more for the actual file
  192.                 pb->c.hFileInfo.ioVRefNum = fss->vRefNum;
  193.                 pb->c.hFileInfo.ioDirID = fss->parID;
  194.                 
  195.                 ioFDirIndexWas = pb->c.hFileInfo.ioFDirIndex;    // Save the value in ioFDirIndex
  196.                 pb->c.hFileInfo.ioFDirIndex = 0;                // Zero ioFDirIndex so PBGetCatInfo won't use indexing
  197.                 
  198.                 // You don't need to copy fss->name to .ioNamePtr here — PBGetCatInfo will do it for us
  199.                 err = PBGetCatInfoSync (&pb->c);
  200.                 
  201.                 pb->c.hFileInfo.ioFDirIndex = ioFDirIndexWas;    // Restore ioFDirIndex
  202.             }
  203.         }
  204.     }
  205.     return err;
  206. }
  207.  
  208. TypeListHndl FREFTypes (short resFork)
  209. {
  210.     short        numFREFs, frefNum, numTypes = 0, saveResFork;
  211.     OSType        type, **fref;
  212.     TypeListHndl    typesHndl = NULL;
  213.     
  214.     if (resFork == kInvalidRefNum)
  215.         return NULL;
  216.         
  217.     saveResFork = CurResFile ();        // Save the current order of open resource forks
  218.     UseResFile (resFork);            // We'll read 'FREF' resources just from this file, since there may be any number of
  219.                                 //    open allication files and we don't want to end up with 'FREF's from all of them!
  220.     numFREFs = Count1Resources ('FREF');
  221.     if (numFREFs != 0) {
  222.         typesHndl = (TypeListHndl) NewHandle (numFREFs * sizeof (OSType) + sizeof (short));
  223.         if (typesHndl != NULL) {
  224.             for (numTypes = 0, frefNum = 1; frefNum <= numFREFs; frefNum++) {
  225.                 fref = (OSType **) Get1IndResource ('FREF', frefNum);
  226.                 if (fref != NULL) {
  227.                     type = **fref;
  228.                     ReleaseResource ((Handle) fref);
  229.                     if (type != 'APPL')                            // Don't count the 'APPL' type — nearly all
  230.                         (*typesHndl)->type[numTypes++] = type;    //    applications have an 'FREF' for this
  231.                 }
  232.             }
  233.             if (numTypes < numFREFs)
  234.                 SetHandleSize ((Handle) typesHndl, numTypes * sizeof (OSType) + sizeof (short));
  235.         }
  236.     }    
  237.     if (typesHndl != NULL)
  238.         (*typesHndl)->numTypes = numTypes;
  239.     
  240.     UseResFile (saveResFork);        // Restore the original order of open resource forks
  241.     return typesHndl;
  242. }
  243.  
  244. Boolean OpenableType (OSType fileType, TypeListHndl openableTypesHndl)
  245. {
  246.     short    i;
  247.     OSType    t, *tp;
  248.     
  249.     if (openableTypesHndl == NULL)
  250.         return FALSE;
  251.         
  252.     tp = &(*openableTypesHndl)->type[0];
  253.     for (i = (*openableTypesHndl)->numTypes; i > 0; i--, tp++) {
  254.         t = *tp;
  255.         if (fileType == 'fold' || fileType == 'disk') {
  256.             if (t == fileType)
  257.                 return TRUE;
  258.         } else if (t == '****' || t == fileType)
  259.             return TRUE;
  260.     }
  261.     return FALSE;        // If we got here, there's no match
  262. }
  263.  
  264. OSErr RefNumToFSSpec (short refNum, FSSpec *fss, Boolean *isResFork)
  265. {
  266.     FCBPBRec    pb;
  267.     OSErr        err;
  268.     
  269.     // See Inside Macintosh IV pp.178–180 for documentation of PBGetFCBInfo
  270.     // NOTE:    There is an apparent typo there — at the bottom of page 180, it says:
  271.     //
  272.     //            "FCBMdRByt (which corresponds to ioFCBFlags in the parameter
  273.     //            block for PBGetFCBInfo) contains flags that describe the status
  274.     //            of the file, as follows:…"
  275.     //
  276.     //        But experience shows that these flags are returned in the HIGH BYTE
  277.     //        of the ioFCBFlags field, not the whole word (in effect, in its low byte)
  278.     //        
  279.     //        Then again, maybe it's just a Pascal bit thing…
  280.     
  281.     pb.ioCompletion = NULL;
  282.     pb.ioVRefNum = 0;            // 0 == check all volumes
  283.     pb.ioNamePtr = fss->name;    // Yes, we need the name of the file — don't worry,
  284.                             //    HFSDispatch (in its guise of PBGetFCBInfo)
  285.                             //    doesn't move or purge memory (whew!)
  286.     pb.ioRefNum = refNum;
  287.     pb.ioFCBIndx = 0L;            // Get info on just this one file
  288.     
  289.     err = PBGetFCBInfoSync (&pb);    // NOTE:    For some strange reason, calling
  290.                                 //        PBGetFCBInfo (&pb, FALSE) here
  291.                                 //        instead gives us a major hang — I
  292.                                 //        have a feeling this is the fault of
  293.                                 //        THINK C's glue routines but I'm not
  294.                                 //        going to bother finding out for sure…
  295.     if (err != noErr)
  296.         return err;
  297.     
  298.     // Fill in the FSSpec — note that fss->name has already been filled in
  299.     fss->vRefNum = pb.ioFCBVRefNum;
  300.     fss->parID = pb.ioFCBParID;    // Inside Macintosh IV implies that pb.ioVRefNum
  301.                             //    returns the volume refnum, but in fact the call
  302.                             //    to PBGetFCBInfo doesn't affect it.  This makes
  303.                             //    sense when you think about it — if it DID return
  304.                             //    the volume refnum in ioVRefNum, you'd have
  305.                             //    to reset it to 0 in each of a sequence of indexed
  306.                             //    calls (with ioFCBIndx going from 1 to n == the
  307.                             //    number of open paths)
  308.     if (isResFork != NULL)
  309.         *isResFork = (pb.ioFCBFlags & 0x0200);
  310.         // 0x0200 == binary 00000010_00000000 — as I mentioned above, it's the
  311.         //    HIGH byte that counts.  Bit 9 of the word == bit 1 of the high byte — Inside
  312.         //    Macintosh IV (bottom of p.180) tells us "[bit] 1 … [is set] if the entry
  313.         //    describes a resource fork"
  314.     
  315.     return noErr;    /* fhs 1994 july 1 */
  316. }
  317.  
  318. OSErr DirectoryContentsLoop (short vRefNum, long dirID, DCLActionProc actionProc, Boolean skipOnError, long refCon)
  319. {
  320.     // Loop through the directory designated by vRefNum and dirID, calling the function actionProc with the
  321.     //    parameter refcon for each thing in the directory.  This function does not recurse through subdirectories.
  322.     
  323.     CInfoPBRec    pb;
  324.     short        i;
  325.     OSErr        err = noErr;
  326.     Str63        name;
  327.     Boolean        keepGoing;
  328.     
  329.     pb.hFileInfo.ioCompletion = NULL;
  330.     pb.hFileInfo.ioNamePtr = &name[0];
  331.     
  332.     for (i = 1, keepGoing = TRUE; keepGoing; i++) {
  333.         pb.hFileInfo.ioVRefNum = vRefNum;
  334.         pb.hFileInfo.ioDirID = dirID;
  335.         pb.hFileInfo.ioFDirIndex = i;
  336.         err = PBGetCatInfoSync (&pb);
  337.         if (err == noErr)
  338.             keepGoing = (*actionProc) (&pb, refCon);
  339.         else if (err == fnfErr || !skipOnError)
  340.             keepGoing = FALSE;
  341.     }
  342.  
  343.     if (err == fnfErr)
  344.         err = noErr;
  345.  
  346.     return err;
  347. }
  348.  
  349.